
//
// 110603a- AH - Created.
// 110603b- AH - (Garage) First version completed.
// 110603c- AH - (Garage) equals(String).
// 110604 - AH - (Garage) Moved match method away from here, moved to 
//               DefaultSoekratNameMatcher, an implementation of 
//               SoekratNameMatcher.
// 110610 - AH - Now use equalsIgnoreCase in equals.
// 110614 - AH - (Bybanen *) Made mutable by introducing set(String).
// 120125 - AH - (Sletten *) Minor java doc missing.
//

package org.soekrat.engine;

import static org.soekrat.engine.util.Util.E_STRING_A;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *   Names in Soekrat data that should match.
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC)
 */
public final class SoekratName 
{
  private String m_name;
  
  private String m_pure;
  
  private List<String> m_starred;
  
  /**
   * <p>
   *   Constructor.
   * </p>
   * @param name Name.
   */
  public SoekratName(String name){ set(name); }
  
  /**
   * <p>
   *   Sets.
   * </p>
   * @param name Name.
   */
  public void set(String name)
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    
    name=name.trim();
    if (name.length()==0)
    {
      throw new IllegalArgumentException("name is the empty String");
    }
    
    m_name=name;
    m_pure=purify(name);
    m_starred=getStarred(name);
  }
  
  /**
   * <p>
   *   Gets version of name with '*' removed.
   * </p>
   * @return Pure name. 
   */
  public String getPure(){ return m_pure; }
  
  /**
   * <p>
   *   Gets starred tokens.
   * </p>
   * @return Stared.
   */
  public String[] getStarred()
  {  
    return m_starred==null ? E_STRING_A : m_starred.toArray(E_STRING_A); 
  }
  
  private static String purify(String name)
  {
    if (name.indexOf('*')==-1) return name;
    StringBuilder sb=new StringBuilder();
    int n=name.length();
    for (int i=0; i<n; i++)
    {
      char c=name.charAt(i);
      if (c!='*') sb.append(c); 
    }
    return sb.toString();
  }
  
  private static List<String> getStarred(String name)
  {
    List<String> retVal=null;
    int idx=name.indexOf('*');
    while (idx!=-1)
    {
      String starred=getStarred(name, idx);
      if (starred!=null)
      {
        if (retVal==null) retVal=new ArrayList<String>();
        retVal.add(starred);
      }
      
      idx=(idx==name.length()-1) ? -1 : name.indexOf('*', idx+1);
    }
    return retVal;
  }
  
  private static String getStarred(String name, int idx)
  {
    if (idx==0) return null;
    
    int to=idx;
    int from=-1;
    
    idx--;
    while (idx>=0 && isNameChar(name.charAt(idx)))
    {
      from=idx;
      idx--;
    }
    
    if (from!=to && from!=-1 && to!=-1)
    {
      String retVal=name.substring(from, to);
      return retVal.length()==0 ? null : retVal;
    }
    return null;
  }
  
  private static boolean isNameChar(char c)
  {
    if (!Character.isWhitespace(c))
    {
      return c!='*';
    }
    return false;
  }
  
  @Override
  public boolean equals(Object o)
  {
    if (o instanceof SoekratName)
    {
      return ((SoekratName)o).m_name.equals(m_name);
    }
    
    return false;
  }
  
  /**
   * <p>
   *   Tells if given 
   *   {@code String} is equal to
   *   {@link #toString()}.
   * </p>
   * <p>
   *   That is a 
   *   {@link SoekratName} created with {@code s} will match the same 
   *   {@link String} as {@code this}.
   * </p>
   * @param s {@code String}.
   * @return {@code true} if is equal, {@code false} if is not.
   */
  public boolean equals(String s)
  {
    if (s==null) return false;
    return m_name.equalsIgnoreCase(s);
  }

  @Override
  public int hashCode(){ return m_name.hashCode(); }

  /**
   * <p>
   *   Gets the 
   *   {@code String} representation {@code this} was created from. 
   * </p>
   * @return {@code String} representation.
   */
  @Override
  public String toString(){ return m_name; }
  
  /**
   * <p>
   *   The empty array shared.
   * </p>
   */
  public static SoekratName[] EMPTY_ARRAY=new SoekratName[0];
  
}
